//
//  ZYDealLockDetector.m
//  ZYWebImage
//
//  Created by wangzhipan on 2025/5/3.
//

#import "ZYDealLockDetector.h"
#import <pthread.h>
#import <UIKit/UIKit.h>
#import "ZYCrashReportGenerator.h"

// 默认死锁检测阈值（秒）
static const NSTimeInterval kDefaultThreshold = 3;

// 检测间隔（秒）
static const NSTimeInterval kDefaultCheckInterval = 0.5;

// 最大检测次数
static const NSUInteger kDefaultMaxCheckTimes = 3;

// 全局变量，用于 RunLoop 观察者回调
static CFAbsoluteTime g_lastUpdateTime = 0;
static bool g_isMonitoring = false;
static NSTimeInterval g_deadlockThreshold = 0;
static CFRunLoopObserverRef g_runloopObserver = NULL;
static pthread_t g_monitorThread = NULL;


@interface ZYDealLockDetector()

//死锁检测阈值
@property (nonatomic, assign) NSTimeInterval threshold;

@property (nonatomic, assign, getter=isRunning) BOOL isRunning;

// 连续检测失败次数
@property (nonatomic, assign) NSUInteger failureTimers;
@property (nonatomic, strong, nullable) NSLock *lock;
@end

@implementation ZYDealLockDetector

//pthread线程处理
static void* monitorThreadEntry(void * info)
{
    //设置线程名，方便出问题定位
    pthread_setname_np("ZYDealLockDetector");
    // 提高线程优先级，确保监控线程不会被阻塞
    int policy = 0;
    sched_param param;
    pthread_getschedparam(pthread_self(), &policy, &param);
    param.sched_priority = sched_get_priority_max(policy);
    pthread_setschedparam(pthread_self(), policy, &param);
    
    ZYDealLockDetector *detector = (__bridge ZYDealLockDetector *)info;
    
    //线程里面无限循环处理事情
    while (g_isMonitoring) {
        @autoreleasepool {
            CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent();
            CFAbsoluteTime diff = currentTime - g_lastUpdateTime;
            if (diff > g_deadlockThreshold) {
                // 主线程超过阈值未响应
                [detector p_handlePotentialDeadlock:diff];
            }
        }
        // 使用 usleep 而不是 NSThread 的 sleep 方法，更精确
        usleep((useconds_t)(kDefaultCheckInterval * 1000000));
    }
    
    return NULL;
}

static void runLoopObserverCallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
    /*
     kCFRunLoopEntry = (1UL << 0),
     kCFRunLoopBeforeTimers = (1UL << 1),
     kCFRunLoopBeforeSources = (1UL << 2),
     kCFRunLoopBeforeWaiting = (1UL << 5),
     kCFRunLoopAfterWaiting = (1UL << 6),
     kCFRunLoopExit = (1UL << 7),
     */
    
    /*为什么是kCFRunLoopBeforeWaiting更新时间
     - 更准确地检测死锁 ：
     如果主线程陷入死锁或长时间阻塞，它将无法到达"进入休眠前"这个状态，因此 g_lastUpdateTime 不会被更新。这正是我们想要检测的情况。
     - 避免误报 ：
     如果在 RunLoop 被唤醒后记录时间戳，可能会出现这种情况：主线程被唤醒后立即进入了死锁状态，但时间戳已经更新，导致检测器需要等待更长时间才能发现问题。
     - 更好地反映用户体验 ：
     从用户体验角度看，主线程能否及时处理完任务并准备接收新任务（即进入休眠状态）是衡量应用响应性的关键。在这个时刻记录时间戳，可以更好地反映用户实际感知到的应用响应情况。
     */
    switch (activity) {
        case kCFRunLoopEntry:
            //进入runloop
            break;
        case kCFRunLoopBeforeTimers:
            //即将处理timers
            break;
        case kCFRunLoopBeforeSources:
            //即将处理sources
            break;
        case kCFRunLoopBeforeWaiting:
            //即将进入休眠，在这里记录时间
            g_lastUpdateTime = CFAbsoluteTimeGetCurrent();
            break;
        case kCFRunLoopAfterWaiting:
            //唤醒
            break;
        case kCFRunLoopExit:
            //退出
            break;
        default:
            break;
    }
}


+ (instancetype)sharedInstance
{
    static id _instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init];
    });
    return _instance;
}

- (instancetype)init
{
    if (self = [super init]) {
        _threshold = kDefaultThreshold;
        _failureTimers = 0;
        _isRunning = NO;
        _lock = [NSLock new];
    }
    return self;
}

- (BOOL)startWithThreshold:(NSTimeInterval)threshold
{
    [self.lock lock];
    
    if (_isRunning) {
        return YES;
    }
    
    self.threshold = threshold > 0 ? threshold : kDefaultThreshold;
    g_deadlockThreshold = self.threshold;
    
    //记录时间
    g_lastUpdateTime = CFAbsoluteTimeGetCurrent();
    self.failureTimers = 0;
    
    // 创建并添加 RunLoop 观察者
    if (!g_runloopObserver) {
        g_runloopObserver = CFRunLoopObserverCreate(NULL,
                                                    kCFRunLoopAllActivities,
                                                    YES,
                                                    0, runLoopObserverCallBack,
                                                    NULL);
        if (g_runloopObserver) {
            CFRunLoopAddObserver(CFRunLoopGetMain(), g_runloopObserver, kCFRunLoopCommonModes);
        }
        else {
            NSLog(@"无法创建 RunLoop 观察者");
            [self.lock unlock];
            return NO;
        }
        
    }
    
    //监控状态更新
    _isRunning = YES;
    g_isMonitoring = YES;
    
    //创建并启动pthread线程
    if (pthread_create(&g_monitorThread, NULL, monitorThreadEntry, (__bridge void *)self) != 0) {
        NSLog(@"无法创建监控线程");
        CFRunLoopRemoveObserver(CFRunLoopGetMain(), g_runloopObserver, kCFRunLoopCommonModes);
        CFRelease(g_runloopObserver);
        g_runloopObserver = NULL;
        g_isMonitoring = NO;
        _isRunning = NO;
        [self.lock unlock];
        return NO;
    }
    
    [self.lock unlock];
    return YES;
}

- (BOOL)start
{
    return [self startWithThreshold:kDefaultThreshold];
}

- (BOOL)isRunning
{
    BOOL result = NO;
    [self.lock lock];
    result = _isRunning;
    [self.lock unlock];
    return result;
}

- (void)stop
{
    [self.lock lock];
    
    if (_isRunning) {
        _isRunning = NO;
        g_isMonitoring = NO;
        
        //等待线程退出
        if (g_monitorThread) {
            pthread_join(g_monitorThread, NULL);
            g_monitorThread = NULL;
        }
        
        // 移除 RunLoop 观察者
        if (g_runloopObserver) {
            CFRunLoopRemoveObserver(CFRunLoopGetMain(), g_runloopObserver, kCFRunLoopCommonModes);
            CFRelease(g_runloopObserver);
            g_runloopObserver = NULL;
        }
    }
    
    [self.lock unlock];
}

#pragma mark - private
- (void)p_handlePotentialDeadlock:(NSTimeInterval)duration
{
    [self.lock lock];
    
    _failureTimers++;
    
    NSLog(@"主线程已经 %.2f 秒未响应，连续 %ld 次检测失败",
              duration, (long)_failureTimers);
    
    // 连续多次检测失败才报告死锁，避免误报
    if (_failureTimers > kDefaultMaxCheckTimes) {
        [self p_generateDeadLockReport:duration];
        _failureTimers = 0;
    }
    [self.lock unlock];
}

- (void)p_generateDeadLockReport:(NSTimeInterval)duration
{
    NSString *name = @"Main Thread Dead Lock!";
    NSString *reason = [NSString stringWithFormat:@"主线程已经 %.2f 秒未响应，可能发生了死锁", duration];
    
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
    
    userInfo[@"duration"] = @(duration);
    
    // 添加应用状态信息
    UIApplicationState appState = [UIApplication sharedApplication].applicationState;
    userInfo[@"applicationState"] = @(appState);
    
    // 添加设备信息
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
    userInfo[@"systemUptime"] = @(processInfo.systemUptime);
    userInfo[@"processorCount"] = @(processInfo.processorCount);
    userInfo[@"activeProcessorCount"] = @(processInfo.activeProcessorCount);
    userInfo[@"physicalMemory"] = @(processInfo.physicalMemory);
    
    // 生成崩溃报告
    [[ZYCrashReportGenerator sharedInstance] generateReportWithType:ZYCrashTypeDeadlock
                                                               name:name
                                                             reason:reason
                                                           userInfo:userInfo];
}

@end
